import {AfterViewInit, Component, EventEmitter, Input, OnInit, Output, TemplateRef, ViewChild} from '@angular/core';
import {
    NzFormatBeforeDropEvent,
    NzFormatEmitEvent,
    NzMessageService,
    NzModalService,
    NzTreeComponent
} from 'ng-zorro-antd';
import {BaseNzTreeNodeOptions, Page, ReturnForm} from '@sb/base/core';
import {STData} from '@delon/abc';
import {Observable, of, Subject, timer} from 'rxjs';
import {catchError} from 'rxjs/operators';
import {BaseTreeService} from '@sb/base/core/service/base-tree.service';
import {BaseTreeSearchConfig} from '@sb/base/core/entity/base-tree-search-config';
import {NzTreeNode} from 'ng-zorro-antd/core/tree/nz-tree-base-node';

@Component({
    selector: 'base-tree',
    templateUrl: './base-tree.component.html',
    styleUrls: ['./base-tree.component.less']
})
export class BaseTreeComponent implements OnInit, AfterViewInit {

    /**
     * 初始化结束
     */
    initFinish = false;
    /**
     * 树节点
     */
    @ViewChild('nzTree', {static: false})
    nzTree: NzTreeComponent;
    /**
     * 选中节点
     */
    activatedNode: NzTreeNode;
    treeContainerHeight: string;
    /**
     * 显示根节点
     */
    @Input()
    showRoot = false;
    /**
     * 根节点对应的名称，只有在showRoot = true 才有效
     */
    @Input()
    globalName = '根节点';
    /**
     * 根节点Id
     */
    @Input()
    rootNodeId = '-1';
    /**
     * 树的数据，仅初始化的时候有效。
     */
    @Input()
    treeData: BaseNzTreeNodeOptions<STData>[] = [];
    /**
     * 搜索文本
     */
    searchText: string;
    /**
     * 选中keyIds
     */
    checkedKeys: string[] = [];
    /**
     * 父子节点是否有区分，
     * 如果选择为true，每个节点相对独立
     */
    @Input()
    checkStrictly = false;
    /**
     * 显示查询结果面板
     */
    showSearchResultPanel = false;
    /**
     * 查询结果
     */
    searchResults: BaseNzTreeNodeOptions<STData>[];
    /**
     * 自定义placeholder
     */
    @Input()
    searchPlaceHolderText = '请输入关键词';
    /**
     * 可拖动
     */
    @Input()
    draggable = false;
    /**
     * 显示图标
     */
    @Input()
    showTypeIcon = false;
    /**
     * 自定义加载方法
     */
    @Input()
    customLoadMethod: (parentId: string, searchConfig: any, maxLevel: number, baseTreeService: BaseTreeService<STData, Page, BaseNzTreeNodeOptions<STData>>) => Observable<ReturnForm<BaseNzTreeNodeOptions<any>[]>>;
    /**
     * 自定义获取父节点方法
     */
    @Input()
    customGetTreeNodePathMethod: (key: string, baseTreeService: BaseTreeService<STData, Page, BaseNzTreeNodeOptions<STData>>) => Observable<ReturnForm<string[]>>;
    /**
     * 自定义搜索方法
     */
    @Input()
    customSearchByTextMethod: (searchText: string, searchConfig: BaseTreeSearchConfig, baseTreeService: BaseTreeService<STData, Page, BaseNzTreeNodeOptions<STData>>) => Observable<ReturnForm<BaseNzTreeNodeOptions<any>[]>>;
    /**
     * 自定义拖动方法
     */
    @Input()
    customDragMethod: (drag: NzTreeNode, target: NzTreeNode, position: number, baseTreeService: BaseTreeService<STData, Page, BaseNzTreeNodeOptions<STData>>) => Observable<ReturnForm<any>>;
    /**
     * 选中
     */
    @Input()
    checkable = false;
    /**
     * 选中并点击
     */
    @Input()
    checkedWhileClick = false;  // 点击节点时选择复选框
    /**
     * 选中回调事件
     */
    @Output()
    checkNode = new EventEmitter<NzTreeNode>();
    /**
     * 类型对应图标
     */
    @Input()
    typeIcon: { [key: string]: string } = {
        root: 'dr:hy-root'
    };
    /**
     * 一次加载多少级
     */
    @Input()
    maxLevel = 1;
    /**
     * 树搜索对象
     */
    @Input()
    searchConfig: BaseTreeSearchConfig;
    @Input()
    showSearch = false;
    @Input()
    beforeDrop: (dragNode: NzTreeNode, targetNode: NzTreeNode, pos: number) => boolean | Observable<boolean>;
    @Input()
    treeNodeTemplate: TemplateRef<{ $implicit: BaseNzTreeNodeOptions<STData>; }>;
    @Output()
    selectNode = new EventEmitter<NzTreeNode>();
    @Output()
    expandChange = new EventEmitter<BaseNzTreeNodeOptions<STData>>();
    @Input()
    customListItem: TemplateRef<any>;
    lastNode;

    constructor(
        public message: NzMessageService,
        private modalService: NzModalService,
        private baseTreeService: BaseTreeService<STData, Page, BaseNzTreeNodeOptions<STData>>
    ) {
    }

    clickNode(data: NzFormatEmitEvent): void {
        if (!data.node.isDisabled) {
            this.activatedNode = data.node;
            // 选中节点
            /* if(this.checkable &&this.checkedWhileClick){
                 data.node.isChecked = !data.node.isChecked;
             }*/
            this.selectNode.emit(data.node);
        }
    }


    ngOnInit() {
        if (this.showRoot) {
            this.treeData = [{
                key: this.rootNodeId,
                title: this.globalName,
                loadedChildren: false,
                expanded: true,
                selected: true,
                isLeaf: false,
                type: 'root',
                data: {}
            }];
        }
        this.initFinish = true;
    }


    ngAfterViewInit(): void {
        let node = this.nzTree.getTreeNodeByKey(this.rootNodeId);
        this.reloadNode(this.rootNodeId, !this.showRoot).subscribe(
            res => {
                if (res && res.success) {
                    if (!this.showRoot) {
                        const message = res.message;
                        node = this.nzTree.getTreeNodeByKey(message[0].key);
                    }
                    this.defaultSelect(node);
                }
            }
        );

        if (this.showSearch) {
            this.treeContainerHeight = 'calc(100% - 42px)';
        } else {
            this.treeContainerHeight = '100%';
        }
    }

    nzOnDrop(event: any) {
        // this.targetNode = event.node;
    }

    nzOnDragOver(event: any) {
        // this.targetNode = null;
    }

    nzOnDragEnter(event: any) {
        if (this.lastNode) {
            this.lastNode.isLeaf = this.lastNode._back_isLeaf;
            delete this.lastNode._back_isLeaf;
        }
        this.lastNode = event.node;
        this.lastNode._back_isLeaf = event.node.isLeaf;
        this.lastNode.isLeaf = false;
    }

    nzOnDragLeave(event: any) {
        // if (event.node && event.node._back_isLeaf) {
        //     event.node.isLeaf = event.node._back_isLeaf;
        //     delete event.node._back_isLeaf;
        // }
    }

    nzBeforeDrop(arg: NzFormatBeforeDropEvent): Observable<boolean> {
        const dragNode = arg.dragNode;
        let targetNode = arg.node;
        let pos = arg.pos;

        let result: Observable<boolean> | boolean = false;
        if (this.beforeDrop) {
            try {
                result = this.beforeDrop(dragNode, targetNode, pos);
            } catch (e) {
                result = false;
            }
        }

        if (pos === -1 || pos === 1) {
            const tempNode = targetNode;
            if (targetNode.parentNode) {
                targetNode = targetNode.parentNode;
                let tempPos = 0;
                for (let i = 0; i < targetNode.children.length; i++) {
                    if (targetNode.children[i] === tempNode) {
                        tempPos = i;
                        break;
                    }
                }
                pos = tempPos + pos;
            }
        }

        if (!(result instanceof Observable)) {
            result = of(result);
        }

        const subject = new Subject<boolean>();

        result.subscribe(value => {

            if (!value) {
                subject.next(false);
                subject.complete();
                this.message.info('不允许移动！');
                return;
            }


            this.modalService.create({
                nzTitle: '系统提示',
                nzContent: '是否进行移动？',
                nzClosable: false,
                nzOnCancel: () => {
                    this.message.info('不允许移动！');
                    subject.next(false);
                    subject.complete();
                },
                nzOnOk: () => {
                    let o: Observable<ReturnForm<any>>;
                    if (this.customDragMethod) {
                        o = this.customDragMethod(dragNode, targetNode, pos, this.baseTreeService);
                    } else {
                        o = this.baseTreeService.drag(dragNode.key, targetNode.key, pos);
                    }

                    o.pipe(
                        catchError((error: any): Observable<any> => {
                            return of(false);
                        })
                    ).subscribe(returnForm => {
                        subject.next(returnForm.success);
                        subject.complete();
                        if (returnForm.success) {
                            this.message.info('移动成功！');
                            this.reloadNode(targetNode.key).subscribe(value1 => {
                                this.triggerClick(targetNode.key);
                            });
                        } else {
                            this.message.info('保存失败！');
                        }
                    });
                }
            });
        });

        return subject;
    }

    openEvent(event: NzFormatEmitEvent): void {
        if (event.eventName === 'expand') {
            const node = event.node;
            if (node && node.getChildren().length === 0 && node.isExpanded) {
                this.reloadNode(node.key);
            }
            this.expandChange.emit(node.origin as BaseNzTreeNodeOptions<STData>);
        }
    }

    searchByText(value: string) {
        if (value) {
            let tem;
            if (this.customSearchByTextMethod) {
                tem = this.customSearchByTextMethod(value, this.searchConfig, this.baseTreeService);
            } else {
                tem = this.baseTreeService.searchByText(value, this.searchConfig);
            }
            tem.subscribe(res => {
                if (res.success) {
                    this.searchResults = res.message;
                    this.showSearchResultPanel = true;
                } else {
                    this.message.error('获取节点数据异常：' + res.errorMessage);
                }
            });
        } else {
            this.showSearchResultPanel = false;
        }
    }

    /**
     * 触发点击事件
     * @param nodeId 节点标识
     */
    triggerClick(nodeId) {
        const treeNode = this.nzTree.getTreeNodeByKey(nodeId);
        const event2 = this.nzTree.nzTreeService.formatEvent('click', treeNode, null);
        this.nzTree.nzClick.emit(event2);
    }

    itemClick(item) {
        const node = this.nzTree.getTreeNodeByKey(item.key);
        if (node != null) {
            this.defaultSelect(node);
            this.showSearchResultPanel = false;
            return;
        }
        if (this.customGetTreeNodePathMethod) {
            this.customGetTreeNodePathMethod(item.key, this.baseTreeService).subscribe(result => {
                if (result.success) {
                    this.reloadNodeByPath(result.message, item.key);
                }
            });
        } else {
            this.baseTreeService.getTreeNodePath(item.key).subscribe(res => {
                if (res.success) {
                    const message = res.message;
                    let parentPath: string[] = [];
                    if (message) {
                        parentPath = message.split(',');
                    }
                    this.reloadNodeByPath(parentPath, item.key);
                }
            });
        }
    }

    reloadNodeByPath(parentPath: string[], selfKey: string) {
        if (parentPath != null && parentPath.length !== 0) {
            const path = parentPath.shift();
            const node = this.nzTree.getTreeNodeByKey(path);
            if (node != null) {
                if (node.getChildren().length === 0) {
                    this.reloadNode(node.key).subscribe(returnForm => {
                        this.reloadNodeByPath(parentPath, selfKey);
                    });
                } else {
                    node.isExpanded = true;
                    this.reloadNodeByPath(parentPath, selfKey);
                }
            } else {
                this.message.error('节点加载异常 , 异常节点Id为 ' + path);
            }
        } else {
            const acNode = this.nzTree.getTreeNodeByKey(selfKey);
            if (acNode != null && !acNode.isDisabled) {
                this.defaultSelect(acNode);
            }
            this.showSearchResultPanel = false;
        }
    }


    reload(): Observable<any> {
        return this.reloadNode(this.rootNodeId, !this.showRoot);
    }

    reloadNode(nodeId, cover = false): Observable<any> {
        const node = this.nzTree.getTreeNodeByKey(nodeId);
        if (node) {
            node.isLeaf = false;
            node.isExpanded = true;
        }
        const subject = new Subject();
        let temp;
        if (this.customLoadMethod) {
            temp = this.customLoadMethod(nodeId, this.searchConfig, this.maxLevel, this.baseTreeService);
        } else {
            temp = this.baseTreeService.getNzTree(nodeId, this.searchConfig, this.maxLevel);
        }
        temp.subscribe(returnForm => {
            if (returnForm.success) {
                if (cover) {
                    // if (nodeId === this.rootNodeId) {
                    //     this.treeData = returnForm.message;
                    //     this.nzTree.initNzData(this.treeData);
                    // } else {
                    //     // 刷新自己
                    //     const parentNode = node.parentNode;
                    //     const childs = parentNode.children;
                    //     let pos = 0;
                    //     for (const childNode of childs) {
                    //         if (childNode === node) {
                    //             break;
                    //         }
                    //         pos++;
                    //     }
                    //     node.remove();
                    //     parentNode.addChildren(returnForm.message, pos);
                    // }
                    this.treeData = returnForm.message;
                    this.nzTree.initNzData(this.treeData);

                    timer(200).subscribe(value => {
                        for (const one of returnForm.message) {
                            if (one.expanded) {
                                const c = this.nzTree.getTreeNodeByKey(one.key);
                                if (c.children.length === 0) {
                                    this.reloadNode(one.key);
                                }
                            }
                        }
                    });

                } else {
                    if (node) {
                        node.clearChildren();
                        node.addChildren(returnForm.message);
                        node.isLeaf = returnForm.message.length === 0;
                        node.isExpanded = true;

                        timer(200).subscribe(value => {
                            for (const one of returnForm.message) {
                                if (one.expanded && !one.isLeaf) {
                                    const c = this.nzTree.getTreeNodeByKey(one.key);
                                    if (c.children.length === 0) {
                                        this.reloadNode(one.key);
                                    }
                                }
                            }
                        });
                    } else {
                        this.nzTree.initNzData(this.treeData);
                    }
                }
            } else {
                this.message.error('加载节点数据异常：' + returnForm.errorMessage);
            }
            timer(100).subscribe(value => {
                subject.next(returnForm);
                subject.complete();
            });
        });
        return subject;
    }

    setDefaultChecked(keys: string[]) {
        this.checkedKeys = keys;
    }

    getTreeNodeTypeIcon(treeNode: BaseNzTreeNodeOptions<STData>) {
        return this.typeIcon[treeNode.type] || 'file';
    }

    defaultSelect(treeNode: NzTreeNode) {
        if (!treeNode.isDisabled && treeNode.origin.key !== this.rootNodeId) {
            treeNode.isSelected = true;
            this.activatedNode = treeNode;
            this.selectNode.emit(treeNode);

            let p = treeNode;
            while (p != null) {
                p.isExpanded = true;
                p = p.parentNode;
            }

            return true;
        }
        const children = treeNode.children;
        for (let i = 0; i < children.length; i++) {
            const child = children[i];
            if (this.defaultSelect(child)) {
                break;
            }
        }
    }

    checkBoxChange($event: NzFormatEmitEvent) {
        this.checkNode.emit($event.node);
    }
}
